require(tidyverse)
require(flowCore)
require(flowClust)
require(openCyto)
require(ggcyto)
require(cowplot)
#require(ggrdiges)
old <- theme_set(theme_minimal(base_size = 14) + panel_border(color = "gray20"))

Background & Goal

In the log dilution experiment, we compared FungaLight to the results of PI and CFU for C. glabrata cells treated with 0, 10, 100 and 1,000 mM hydrogen peroxide. We noted there that FungaLight seems to provide better separation in its score between the 100 mM and 1M treated sample than CFU and PI did. This led us to question whether FungaLight can be useful in distinguishing the levels of damage caused by different sublethal doses of hydrogen peroxide, for which CFU would give non-distinguishable readings.

Hanxi therefore performed an experiment on 2024-04-05 to 04-10, using a linear concentration series of hydrogen peroxide. This notebook records the pre-processing of that data and plotting the results.

C. glabrata post-treatment cells were stained with FungaLight (PI+SYTO9), and run through flow cytometry. The same sample was also plated for CFU.

Import data

FCS files are stored in rdss/Users/Hanxi/flow cytometry under the above dates. They are copied to this repository under the same names.

# use relative path to make it easier for collaboration
data.path = "../input/20240405-10 linear H2O2 correlation Cg"
dat0 <- read.flowSet(path = data.path, pattern = "*.fcs",
                     transformation = FALSE,  # the original values are already linearized. 
                     emptyValue = FALSE,  alter.names = TRUE,   # change parameter names to R format
                     column.pattern = ".H|FSC|SSC") # only load the height variables for the fluorescent parameters

Simplify the sample names

oriNames <- sampleNames(dat0)
tmp <- str_split(oriNames, pattern = "[ _]+", simplify = TRUE)[,c(1, 5)]
colnames(tmp) <- c("Date", "Treatment")
#treatment.levels <- c("mock", "5C", "10", "100", "1000")
sample <- data.frame(tmp) %>% 
  mutate(
    Date = mdy(Date),
    Treatment = gsub("\\.fcs", "", Treatment), # remove suffix
    Treatment = fct_inseq(Treatment),
    name = paste(format(Date, "%Y%m%d"), paste0(Treatment, "mM"), sep = "_")
  )
rownames(sample) <- oriNames
dat <- dat0 # make a copy
pData(dat) <- sample
write_tsv(pData(dat), file = "../input/20240405-linear-h2o2-cg-sample.tsv")

Gatting strategies

Load all gates from specification file

source("../script/20250206-FGL-flow-gate-specification.R")

Gating for singlets

The following gaphing steps are used to gate singlets by FSC and SSC values. Only singlets are included in analysis. Gate for outlier

#outlier.gate <- rectangleGate(filterId = "-outlier", "FSC.H" = c(1.2e5, 1e6), "SSC.H" = c(1e2, 1e6))
ggcyto(dat[1], aes(x = FSC.H, y = SSC.H), subset = "root") +
  geom_hex(bins = 64) + geom_gate(outlier.gate) + facet_wrap(~name, ncol = 2) + ggcyto_par_set(limits = "instrument")
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Add gate to GS

gs <- GatingSet(dat) # create a GatingSet
# rename the samples
sampleNames(gs) <- pData(gs)$name
# add the outlier gate
gs_pop_add(gs, outlier.gate, parent = "root")
[1] 2
recompute(gs)
done!

Gate for singlets

scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(30,300)))
ex <- Subset(dat[[1]], outlier.gate)
#polygon <- matrix(c(1e5, 1e5, 1e6, 1e6, 
#                    60, 105, 135,60), ncol = 2)
#colnames(polygon) <- c("FSC.H", "FSC.W")
#singlet.gate <- polygonGate(filterId = "singlet", boundaries = polygon)
ggcyto(ex, aes(x = FSC.H, y = FSC.W)) + geom_hex(bins = 128) + geom_gate(singlet.gate) + geom_stats() + scPars
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Add this gate to the gatingSet

gs_pop_add(gs, singlet.gate, parent = "-outlier", name = "singlet")
[1] 3
recompute(gs)
done!

Gate for live cells

This is the live population with red fluorescence below 10^2.2

Main takeaway

  1. Different from the last (log-dilution series) experiment, where we observed a large difference in %live between the mock and 100 mM treated cells, in this experiment the difference was not only variable across replicates but also much more modest, with the biggest change from 92% to 56%

  2. %live drops to zero practically at 0.5M or above.

scPars <- ggcyto_par_set(limits = list(x = c(0,10^5.5), y = c(0,10^5.5)))
dates <- unique(pData(gs)$Date)
#polygon <- matrix(c(0, 5*10^3, 5*10^3, 0, # BL1.H, green
#                    10^2.2, 10^2.2, 0, 0),# BL3.H, red
#                  ncol = 2)
#colnames(polygon) <- c("BL1.H", "BL3.H")
#live.gate <- polygonGate(filterId = "live", .gate = polygon)
p.axis <- list(
  scale_x_logicle(breaks = 10^c(2,3,4,5)),
  scale_y_logicle(breaks = 10^c(2,3,4,5)),
  theme(
    strip.text = element_text(size = rel(1.1), face = 2)
  )
)

for(date in dates){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = BL1.H, y = BL3.H), subset = "singlet") + 
    geom_hex(bins = 128) + 
    geom_gate(live.gate) +
    geom_stats(location = "data", adjust = c(0.005, 5), digits = 1) + 
    labs(title = paste0("Date: ", date)) +
    facet_wrap(~ fct_inseq(Treatment)) +
    p.axis + scPars
  print(p)
}
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Add this gate to the gatingSet

gs_pop_add(gs, live.gate, parent = "singlet", name = "live")
[1] 4
recompute(gs)
done!

Gate for the intermediate population with high SYTO9

This is the intermediate population with high Red and Green. We hypothesize that they represent oxidatively damaged cells with partially compromised plasma membranes, resulting in more SYTO9 accumulation but not a significant increase in PI.

Main takeaway

  1. For some reason, the percentage reported by geom_stats() is way off for 0.5 - 1M treated samples

  2. % intermediate population peaked at 250 mM dose. Again, from 0.5M and up, we don’t see much distinction among the samples.

#polygon <- matrix(c(10^5, 1*10^3, 10^5,
#                    10^2.2, 10^2.2, 10^4), ncol = 2)
#polygon <- matrix(c(10^3, 10^5.5, 10^5.5,   # BL1.H, green
#                    10^2.2, 10^2.2, 10^4.5),# BL3.H, red
#                  ncol = 2)
#colnames(polygon) <- c("BL1.H", "BL3.H")
#inter.gate <- polygonGate(filterId = "inter", .gate = polygon)
for(date in dates){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = BL1.H, y = BL3.H),
              subset = "singlet") + 
    geom_hex(bins = 128) + 
    geom_gate(inter.gate) + 
    geom_stats(location = "data", adjust = c(0.05, 5)) + 
    labs(title = paste0("Date: ", date)) +
    facet_wrap(~ fct_inseq(Treatment)) +
    p.axis + scPars
  print(p)
}
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Plot to illustrate staining pattern

Show an example of the staining pattern with one replicate

scPars <- ggcyto_par_set(limits = list(x = c(0,10^5), y = c(0,10^4)))
p.ex <- ggcyto(gs[pData(gs)$Date == "2024-04-10"], 
               aes(x = BL1.H, y = BL3.H), subset = "singlet") + 
  geom_hex(bins = 64) + 
  geom_gate("live", colour = "gray20") + 
  #geom_stats(location = "data", adjust = c(0.05, 5)) + 
  labs(title = NULL) +
  facet_wrap(~ fct_inseq(Treatment)) +
  p.axis + scPars
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
p.ex
ggsave("../output/20250120-linear-h2o2-example-FGL-staining.png", 
       plot = p.ex + labs(title = NULL, x = NULL, y = NULL) +
         theme(strip.text = element_text(size = rel(0.8), face = 1),
               axis.text = element_text(size = rel(0.8))),
       width = 3.6, height = 3.2)

Extract gated stats and MFI

% of events in each of the three gates

# we are only interested in the populations after singlet gating
nodes <- c("singlet", "intermediate", "live")
# get the event count
gated_cnt <- gs_pop_get_stats(gs, nodes, type = "count")
# get the MFI for each parameter in each population of interest
gated_mfi <- gs_pop_get_stats(gs, nodes, type = pop.MFI) %>% 
  select(sample, pop, starts_with("FungaLight"))

Combine the data and meta data

gated_stats <- full_join(gated_cnt, gated_mfi, by = c("sample", "pop")) %>% 
  right_join(pData(gs), by = c("sample" = "name")) %>% 
  relocate(Date, Treatment, .after = sample) %>% 
  relocate(sample, .after = last_col()) %>% 
  arrange(Date, as.numeric(Treatment))
write_tsv(gated_stats, file = "../output/20240405-linear-h2o2-Cg-gated-stats.tsv")

# we don't need the MFI for the latter analysis. add meta data to gated_cnt
gated_freq <- left_join(sample, gated_cnt, by = c("name" = "sample")) %>% 
  select(-name) %>% 
  group_by(Date, Treatment) %>% 
  mutate(perc = count / count[pop == "singlet"], .after = count,
         Treatment = fct_inseq(Treatment)) %>% 
  arrange(Date, Treatment)
#gated_stats <- gs_pop_get_stats(gs, type = "count") %>% 
#  as_tibble() %>% 
#  mutate(pop = gsub(".*/", "", pop), pop = gsub("-outlier", "cells", pop)) %>% 
#  pivot_wider(names_from = pop, names_prefix = "n_", values_from = count) %>% 
#  mutate(
#    #p_singlet = n_singlet / n_cells,
#    p_live = n_live / n_singlet,
#    p_intermediate = n_intermediate / n_singlet,
#    p_dead = 1 - p_live - p_intermediate
#  )
#write_tsv(gated_data, file = "../Input/20240124-fig-2-Dye-Order-gated-ht.tsv")
#print(gated_data)
final <- select(pData(dat), sample = name, everything()) %>% 
  left_join(select(gated_stats, -starts_with("n_")),  by = "sample") %>% 
  left_join(popMFI, by = "sample")

write_tsv(final, file = "../output/12.03-gated-output-20240214.tsv")
print(final %>% select(-sample))

Compare with CFU

Read CFU data

Here are the raw cfu data

cfu_raw <- read_tsv("../input/20240214-0405-h2o2-Cg-CFU-raw.tsv",
                    col_types = "cccccciiii", comment = "#")
cfu_calc <- cfu_raw %>% 
  select(Date, Treatment = H2O2_mM, Group, Dilution, Total) %>% 
  mutate(Date = ymd(Date),
         Treatment = fct_inseq(Treatment),
         CFU = Dilution * Total) %>% 
  # we only need the linear range experiment
  dplyr::filter(Date > ymd("20240401")) %>% 
  # group by Date to calculate the ratio of MO to MM
  group_by(Date) %>% 
  mutate(p_live = CFU / CFU[Group == "MM"])

Calculate survival from FungaLight

We calculate the percent live as the FGL survival. We also record the percent intermediate events and will investigate its utility for distinguishing doses not distinguishable by CFU.

dye_based <- gated_freq %>% 
  # record the total number of events as the count of singlets
  group_by(Date, Treatment) %>% 
  mutate(total = count[pop == "singlet"]) %>% 
  # now we don't need the singlet population and the count variable
  select(-count) %>% 
  dplyr::filter(pop != "singlet") %>%
  #ungroup() %>% 
  # we will pivot this data frame to a wider format, making 
  # two new variables out of the percentage variable
  pivot_wider(names_from = pop, values_from = perc, names_prefix = "p_") %>% 
  mutate(p_dead = 1 - p_live - p_intermediate) %>% 
  relocate(p_live, .after = total)
PI <- final %>% 
  dplyr::filter(Dye == "PI") %>% 
  select(Date, Treatment, Method = Dye, Score = p_live)

FGL <- final %>% 
  dplyr::filter(Dye == "Both") %>% 
  mutate(
    wFGL = p_live * 2/log(BL1_live, 10)
  ) %>% 
  select(Date, Treatment, wFGL, FGL = p_live) %>% 
  pivot_longer(cols = c(wFGL, FGL), names_to = "Method", values_to = "Score")
  

all <- bind_rows(
  PI, FGL,
  mutate(cfu, Method = "CFU") %>% rename(Score = CFU)
) 

Plotting the results

CFU survival

p.cfu <- cfu_calc %>% 
  ggplot(aes(x = Treatment, y = p_live)) +
  geom_bar(stat = "summary", fun = "mean", fill = "gray70", width = 0.8) +
  geom_point(aes(shape = as.character(Date)), 
             position = position_jitter(0.1),
             size = 1.5) + 
  scale_shape_manual(values = 4:6, guide = "none") +
  scale_y_continuous(labels = scales::percent, 
                     limits = c(NA, 1.05), breaks = seq(0,1,0.5)) +
  labs(title = "CFU", x = bquote(H[2]*O[2]~(mM)), y = "% Live") +
  theme(strip.text = element_text(size = rel(1.2), face = 2),
        strip.background = element_blank(),
        plot.title = element_text(hjust = 0.5))

p.cfu

FungaLight results

p.dye <- dye_based %>% 
  ggplot(aes(x = Treatment, y = p_live)) +
  geom_bar(stat = "summary", fun = "mean", fill = "gray70", width = 0.8) +
  geom_point(aes(shape = as.character(Date)), 
             position = position_jitter(0.1),
             size = 1.5) + 
  # overlay the p_intermediate points
  stat_summary(aes(y = p_intermediate), geom = "point", shape = 95,
            fun = "mean", size = 5, color = "steelblue3") +
  stat_summary(aes(y = p_intermediate, group = NA), geom = "line",
            fun = "mean", color = "steelblue") +
  geom_point(aes(y = p_intermediate, shape = as.character(Date)),
             position = position_jitter(0.1),
             color = "steelblue", size = 1.5, stroke = 1.5) + 
  scale_shape_manual(values = 4:6, guide = "none") +
  scale_y_continuous(labels = scales::percent, 
                     limits = c(NA, 1.05), breaks = seq(0,1,0.5)) +
  labs(title = "FungaLight", x = bquote(H[2]*O[2]~(mM)), y = "% Live") +
  theme(strip.text = element_text(size = rel(1.2), face = 2),
        strip.background = element_blank(),
        plot.title = element_text(hjust = 0.5))

p.dye

Alternative bar plots

p.dye.side_by_side <- dye_based %>% 
  select(Date, Treatment, p_live, p_intermediate) %>% 
  pivot_longer(cols = c(p_live, p_intermediate), 
               names_to = "par", values_to = "perc") %>% 
  mutate(par = factor(par, levels = c("p_live", "p_intermediate"),
                      labels = c("% live", "% intermediate"))) %>% 
  ggplot(aes(x = Treatment, y = perc, group = par)) +
  geom_bar(aes(fill = par), position = position_dodge(0.9),
           stat = "summary", fun = "mean", width = 0.8) +
  geom_point(aes(shape = as.character(Date), color = par), 
             position = position_jitterdodge(jitter.width = 0.1,
                                             dodge.width = 0.9),
             size = 1.2) + 
  scale_fill_manual(NULL, values = c("gray70", "lightblue2")) +
  scale_color_manual(NULL, values = c("black", "steelblue")) +
  scale_shape_manual(values = 4:6, guide = "none") +
  scale_y_continuous(labels = scales::percent, 
                     limits = c(NA, 1.05), breaks = seq(0,1,0.5)) +
  labs(title = "FungaLight", x = bquote(H[2]*O[2]~(mM)), y = NULL) +
  theme(strip.text = element_text(size = rel(1.2), face = 2),
        strip.background = element_blank(),
        plot.title = element_text(hjust = 0.5),
        legend.position = "inside",
        legend.position.inside = c(0.8, 0.9))

p.dye.side_by_side

Assemble the plot

plot_grid(
  p.cfu + labs(x = NULL, y = NULL) +
    theme(axis.text.x = element_blank(),
          title = element_text(size = rel(0.7)),
          axis.text = element_text(size = rel(0.7))),
  p.dye.side_by_side + labs(x = NULL, y = NULL) +
    theme(title = element_text(size = rel(0.7)),
          axis.text = element_text(size = rel(0.7)),
          legend.position = "none"),
  nrow = 2, rel_heights = c(1, 1.2)
)
ggsave("../output/20250120-linear-h2o2-CFU-FGL-compare.png",
       width = 3.1, height = 3.1)

Statistical tests

We use Tukey HSD test to compare all pairs of conditionsn for CFU

tmp <- aov(p_live ~ Treatment, data = cfu_calc)
TukeyHSD(tmp)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = p_live ~ Treatment, data = cfu_calc)

$Treatment
                  diff         lwr         upr     p adj
100-0    -9.352686e-01 -0.96550789 -0.90502935 0.0000000
250-0    -9.997259e-01 -1.02996516 -0.96948663 0.0000000
500-0    -9.999891e-01 -1.03022834 -0.96974980 0.0000000
750-0    -9.999891e-01 -1.03022834 -0.96974980 0.0000000
1000-0   -1.000000e+00 -1.03023927 -0.96976073 0.0000000
250-100  -6.445728e-02 -0.09469654 -0.03421801 0.0001301
500-100  -6.472045e-02 -0.09495972 -0.03448118 0.0001250
750-100  -6.472045e-02 -0.09495972 -0.03448118 0.0001250
1000-100 -6.473138e-02 -0.09497065 -0.03449211 0.0001248
500-250  -2.631738e-04 -0.03050244  0.02997609 1.0000000
750-250  -2.631738e-04 -0.03050244  0.02997609 1.0000000
1000-250 -2.741035e-04 -0.03051337  0.02996516 1.0000000
750-500   9.251971e-17 -0.03023927  0.03023927 1.0000000
1000-500 -1.092966e-05 -0.03025020  0.03022834 1.0000000
1000-750 -1.092966e-05 -0.03025020  0.03022834 1.0000000

For p_live with FungaLight

tmp <- aov(p_live ~ Treatment, data = dye_based)
TukeyHSD(tmp)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = p_live ~ Treatment, data = dye_based)

$Treatment
                  diff        lwr         upr     p adj
100-0    -0.1298926649 -0.3394148  0.07962944 0.3562860
250-0    -0.8678501009 -1.0773722 -0.65832800 0.0000001
500-0    -0.9469346756 -1.1564568 -0.73741257 0.0000000
750-0    -0.9478779476 -1.1574001 -0.73835584 0.0000000
1000-0   -0.9481361662 -1.1576583 -0.73861406 0.0000000
250-100  -0.7379574360 -0.9474795 -0.52843533 0.0000007
500-100  -0.8170420107 -1.0265641 -0.60751991 0.0000002
750-100  -0.8179852826 -1.0275074 -0.60846318 0.0000002
1000-100 -0.8182435013 -1.0277656 -0.60872140 0.0000002
500-250  -0.0790845747 -0.2886067  0.13043753 0.7961753
750-250  -0.0800278466 -0.2895500  0.12949426 0.7885837
1000-250 -0.0802860653 -0.2898082  0.12923604 0.7864874
750-500  -0.0009432719 -0.2104654  0.20857883 1.0000000
1000-500 -0.0012014906 -0.2107236  0.20832061 1.0000000
1000-750 -0.0002582187 -0.2097803  0.20926389 1.0000000

For p_intermediate with FungaLight

tmp <- aov(p_intermediate ~ Treatment, data = dye_based)
TukeyHSD(tmp)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = p_intermediate ~ Treatment, data = dye_based)

$Treatment
                  diff         lwr         upr     p adj
100-0     0.1124892688 -0.08745318  0.31243172 0.4516826
250-0     0.5711061447  0.37116370  0.77104859 0.0000066
500-0    -0.0415257799 -0.24146823  0.15841667 0.9787052
750-0    -0.0450275307 -0.24496998  0.15491492 0.9699612
1000-0   -0.0452750554 -0.24521750  0.15466739 0.9692633
250-100   0.4586168759  0.25867443  0.65855933 0.0000631
500-100  -0.1540150487 -0.35395750  0.04592740 0.1739532
750-100  -0.1575167995 -0.35745925  0.04242565 0.1589407
1000-100 -0.1577643242 -0.35770677  0.04217813 0.1579233
500-250  -0.6126319246 -0.81257437 -0.41268948 0.0000031
750-250  -0.6161336754 -0.81607612 -0.41619123 0.0000029
1000-250 -0.6163812001 -0.81632365 -0.41643875 0.0000029
750-500  -0.0035017508 -0.20344420  0.19644070 0.9999999
1000-500 -0.0037492755 -0.20369172  0.19619317 0.9999998
1000-750 -0.0002475247 -0.20018997  0.19969492 1.0000000
plot_grid(
  p.cfu + scale_x_discrete(limits = rev) + coord_flip(),
  p.dye + scale_x_discrete(limits = rev) + coord_flip() + 
    theme(axis.title.y = element_blank(), axis.text.y = element_blank()),
  rel
)

all %>% 
  dplyr::filter(!Treatment %in% c("mock", "5C"), Method != "wFGL") %>% 
  mutate(Method = fct_relevel(Method, "CFU", "FGL", "PI")) %>% 
  ggplot(aes(x = Treatment, y = Score)) +
  geom_bar(stat = "summary", fun = "mean", fill = "gray") +
  #geom_point(size = 2, position = position_jitter(0.05)) + 
  stat_summary(fun.data = "mean_sdl", fun.args = list(mult = 1), 
               geom = "errorbar",  width = 0.1) +
  labs(x = bquote(H[2]*O[2]~(mM)), y = "% Live") +
  facet_wrap(~Method, nrow = 1) +
  theme_cowplot() +
  theme(strip.text = element_text(size = rel(1.2), face = 2),
        strip.background = element_blank())
ggsave("../output/20240323-for-R35-CFU-compared-with-FGL-and-PI.png", width = 5, height = 3)

Example of sample-to-sample variability, using 100 mM treated sample as case

p <- ggcyto(gs[pData(gs)$Treatment %in% c("100", "250")],
            aes(x = BL1.H, y = BL3.H), subset = "singlet") +
  geom_hex(bins = 64) +
  geom_gate(live.gate) +
  geom_stats(location = "gate", adjust = c(2, 0.5), digits = 1) +
  facet_grid(Treatment ~ Date) + 
  labs(title = NULL) +
  p.axis + scPars
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
p
ggsave("../output/20250214-example-variability-between-replicates.png", 
       width = 5, height = 3.5)


Below are hanxi’s plotting code

combined_data <- read_tsv("/space/htang5/Documents/FUN1_data_analysis/biol-4386-course-project-htang5/Methods Paper Writing/02-FungaLight-Distinguishing-Power/Input/20240219-PI-Both-Distinguishing-Power-gated-CFU-ht.tsv")
print(combined_data)
combined_data %>% 
  dplyr::filter(Dye %in% c("Both")) %>% 
  dplyr::filter(Treatment %in% c("0", "10", "100")) %>% 
  ggplot(aes(x = FGS, y = CFU_Survival)) +
  geom_point(aes(color = Treatment))

combined_data %>% 
  dplyr::filter(Dye %in% c("Both")) %>% 
  ggplot(aes(x = Treatment, y = FGS)) +
  geom_point(aes(color = Date))

combined_data %>% 
  dplyr::filter(Dye %in% c("Both")) %>% 
  ggplot(aes(x = Treatment, y = percent_inter)) +
  geom_point(aes(color = Date))
#ggsave("../output/20240104-PI-Dilutions-Gated_RP-Plot.png", width = 7, height = 5)
combined_data$new_FGS <- 1*combined_data$percent_Live - 0.6*combined_data$percent_inter - combined_data$percent_Dead
pf1g <- combined_data %>%
  pivot_longer(cols = c(CFU_Survival, new_FGS),
               names_to = "Assay",
               values_to = "Survival") %>% 
  dplyr::filter(!(Dye %in% c("PI"))) %>% 
  dplyr::filter(!(Treatment %in% c("5C")))  %>%
     mutate(Assay = factor(Assay, levels = c("CFU_Survival", "new_FGS"), labels = c("CFU", "FGL"))) %>% 
  #mutate(Dilution = factor(Dilution, levels = c("250 x", "500 x", "1000 x", "2000 x"))) %>%
  ggplot(aes(x = Assay, y = Survival)) +
  facet_wrap(~ Treatment, nrow = 1, labeller = as_labeller(c("0" = "0 mM", "10" = "10 mM", "100" = "100 mM", "1000" = "1000 mM"))) +
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange", color = "red2",
               size = 0.8, position = position_nudge(x = 0.2)) +
  geom_point(stroke = 1, size = 2, position = position_jitter(0.01)) +
  scale_y_continuous() +
  theme_minimal()

pf1g +
  labs(x = "Assay Type", y = "Survival Quantification") +
  panel_border(color = "black", size = 1.5) +
  theme(axis.line = element_blank(),
        strip.background = element_blank(),
        axis.text.x = element_text(size = 20, face = "bold", color = "black"),  # Adjust size and face (bold)
        axis.text.y = element_text(size = 20, face = "bold", color = "black"),
        axis.title.x = element_text(size = 20, face = "bold"),
        axis.title.y = element_text(size = 20, face = "bold")
        )+ 
  theme(strip.text = element_text(size = 20, face = "bold")) 
ggsave("../output/20240301-Cg-Log-Gated_.png", width = 7, height = 5)
combined_data$percent_PIDead <- 1 - (combined_data$n_PIDead / combined_data$n_singlet)
p <- combined_data %>%
  pivot_longer(cols = c(CFU_Survival, percent_PIDead),
               names_to = "PIAssay",
               values_to = "PISurvival") %>% 
  dplyr::filter(!(Dye %in% c("Both"))) %>% 
  dplyr::filter(!(Treatment %in% c("5C")))  %>%
     mutate(PIAssay = factor(PIAssay, levels = c("CFU_Survival", "percent_PIDead"), labels = c("CFU", "PI"))) %>% 
  #mutate(Dilution = factor(Dilution, levels = c("250 x", "500 x", "1000 x", "2000 x"))) %>%
  ggplot(aes(x = PIAssay, y = PISurvival)) +
  facet_wrap(~ Treatment, nrow = 1, labeller = as_labeller(c("0" = "0 mM", "10" = "10 mM", "100" = "100 mM", "1000" = "1000 mM"))) +
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange", color = "red2",
               size = 0.8, position = position_nudge(x = 0.2)) +
  geom_point(stroke = 1, size = 2, position = position_jitter(0.01)) +
  scale_y_continuous() +
  theme_minimal()

p +
  labs(x = "Assay Type", y = "Survival Quantification") +
  panel_border(color = "black", size = 1.5) +
  theme(axis.line = element_blank(),
        strip.background = element_blank(),
        axis.text.x = element_text(size = 20, face = "bold", color = "black"),  # Adjust size and face (bold)
        axis.text.y = element_text(size = 20, face = "bold", color = "black"),
        axis.title.x = element_text(size = 20, face = "bold"),
        axis.title.y = element_text(size = 20, face = "bold")
        )+ 
  theme(strip.text = element_text(size = 20, face = "bold")) 
ggsave("../output/20240301-Cg-Log-Gated-PI.png", width = 7, height = 5)
pf1g <- combined_data %>%
  dplyr::filter(!(Dye %in% c("Both"))) %>% 
  dplyr::filter(!(Treatment %in% c("1000", "5C")))  %>%
  #mutate(Dilution = factor(Dilution, levels = c("250 x", "500 x", "1000 x", "2000 x"))) %>%
  ggplot(aes(x = Treatment, y = CFU_Survival)) +
  facet_wrap(~ Dye, scale = "free_y") +
  geom_boxplot() +
  geom_point(stroke = 1, size = 2, position = position_jitter(0.2)) +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal()
pf1g +
  labs(x = "Hydrogen Peroxide Treatment Concentration", y = "CFU Survival") +
  panel_border(color = "black", size = 1.5) +
  theme(axis.line = element_blank(),
        strip.background = element_blank(),
        axis.text.x = element_text(size = 12, face = "bold", color = "black"),  # Adjust size and face (bold)
        axis.text.y = element_text(size = 16, face = "bold", color = "black"),
        axis.title.x = element_text(size = 16, face = "bold"),
        axis.title.y = element_text(size = 16, face = "bold")
        )+ 
  theme(strip.text = element_text(size = 16, face = "bold")) 
#ggsave("../output/20240104-PI-Dilutions-Gated_RP-Plot.png", width = 7, height = 5)

—>

LS0tCnRpdGxlOiAiQ29tcGFyZSBDRlUgYW5kIEZ1bmdhTGlnaHQgZm9yIGxpbmVhciBkaWx1dGlvbiBvZiBIMk8yIgphdXRob3I6IEhhbnhpIFRhbmcsIEJpbiBIZQpkYXRlOiAiMjAyNS0wMS0xMyAodXBkYXRlZCBgciBTeXMudGltZSgpYCkiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFfQpyZXF1aXJlKHRpZHl2ZXJzZSkKcmVxdWlyZShmbG93Q29yZSkKcmVxdWlyZShmbG93Q2x1c3QpCnJlcXVpcmUob3BlbkN5dG8pCnJlcXVpcmUoZ2djeXRvKQpyZXF1aXJlKGNvd3Bsb3QpCiNyZXF1aXJlKGdncmRpZ2VzKQpgYGAKCmBgYHtyfQpvbGQgPC0gdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsgcGFuZWxfYm9yZGVyKGNvbG9yID0gImdyYXkyMCIpKQpgYGAKCiMgQmFja2dyb3VuZCAmIEdvYWwKSW4gdGhlIFtsb2cgZGlsdXRpb24gZXhwZXJpbWVudF0oMjAyNDAzMjEtbG9nLWgybzItY2Z1LXZzLWZ1bmdhbGlnaHQuUm1kKSwgd2UgY29tcGFyZWQgRnVuZ2FMaWdodCB0byB0aGUgcmVzdWx0cyBvZiBQSSBhbmQgQ0ZVIGZvciBfQy4gZ2xhYnJhdGFfIGNlbGxzIHRyZWF0ZWQgd2l0aCAwLCAxMCwgMTAwIGFuZCAxLDAwMCBtTSBoeWRyb2dlbiBwZXJveGlkZS4gV2Ugbm90ZWQgdGhlcmUgdGhhdCBGdW5nYUxpZ2h0IHNlZW1zIHRvIHByb3ZpZGUgYmV0dGVyIHNlcGFyYXRpb24gaW4gaXRzIHNjb3JlIGJldHdlZW4gdGhlIDEwMCBtTSBhbmQgMU0gdHJlYXRlZCBzYW1wbGUgdGhhbiBDRlUgYW5kIFBJIGRpZC4gVGhpcyBsZWQgdXMgdG8gcXVlc3Rpb24gd2hldGhlciBGdW5nYUxpZ2h0IGNhbiBiZSB1c2VmdWwgaW4gZGlzdGluZ3Vpc2hpbmcgdGhlIGxldmVscyBvZiBkYW1hZ2UgY2F1c2VkIGJ5IGRpZmZlcmVudCBzdWJsZXRoYWwgZG9zZXMgb2YgaHlkcm9nZW4gcGVyb3hpZGUsIGZvciB3aGljaCBDRlUgd291bGQgZ2l2ZSBub24tZGlzdGluZ3Vpc2hhYmxlIHJlYWRpbmdzLgoKSGFueGkgdGhlcmVmb3JlIHBlcmZvcm1lZCBhbiBleHBlcmltZW50IG9uIDIwMjQtMDQtMDUgdG8gMDQtMTAsIHVzaW5nIGEgbGluZWFyIGNvbmNlbnRyYXRpb24gc2VyaWVzIG9mIGh5ZHJvZ2VuIHBlcm94aWRlLiBUaGlzIG5vdGVib29rIHJlY29yZHMgdGhlIHByZS1wcm9jZXNzaW5nIG9mIHRoYXQgZGF0YSBhbmQgcGxvdHRpbmcgdGhlIHJlc3VsdHMuCgpfQy4gZ2xhYnJhdGFfIHBvc3QtdHJlYXRtZW50IGNlbGxzIHdlcmUgc3RhaW5lZCB3aXRoIEZ1bmdhTGlnaHQgKFBJK1NZVE85KSwgYW5kIHJ1biB0aHJvdWdoIGZsb3cgY3l0b21ldHJ5LiBUaGUgc2FtZSBzYW1wbGUgd2FzIGFsc28gcGxhdGVkIGZvciBDRlUuCgojIEltcG9ydCBkYXRhCj4gRkNTIGZpbGVzIGFyZSBzdG9yZWQgaW4gcmRzcy9Vc2Vycy9IYW54aS9mbG93IGN5dG9tZXRyeSB1bmRlciB0aGUgYWJvdmUgZGF0ZXMuIFRoZXkgYXJlIGNvcGllZCB0byB0aGlzIHJlcG9zaXRvcnkgdW5kZXIgdGhlIHNhbWUgbmFtZXMuCgpgYGB7cn0KIyB1c2UgcmVsYXRpdmUgcGF0aCB0byBtYWtlIGl0IGVhc2llciBmb3IgY29sbGFib3JhdGlvbgpkYXRhLnBhdGggPSAiLi4vaW5wdXQvMjAyNDA0MDUtMTAgbGluZWFyIEgyTzIgY29ycmVsYXRpb24gQ2ciCmRhdDAgPC0gcmVhZC5mbG93U2V0KHBhdGggPSBkYXRhLnBhdGgsIHBhdHRlcm4gPSAiKi5mY3MiLAogICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm1hdGlvbiA9IEZBTFNFLCAgIyB0aGUgb3JpZ2luYWwgdmFsdWVzIGFyZSBhbHJlYWR5IGxpbmVhcml6ZWQuIAogICAgICAgICAgICAgICAgICAgICBlbXB0eVZhbHVlID0gRkFMU0UsICBhbHRlci5uYW1lcyA9IFRSVUUsICAgIyBjaGFuZ2UgcGFyYW1ldGVyIG5hbWVzIHRvIFIgZm9ybWF0CiAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi5wYXR0ZXJuID0gIi5IfEZTQ3xTU0MiKSAjIG9ubHkgbG9hZCB0aGUgaGVpZ2h0IHZhcmlhYmxlcyBmb3IgdGhlIGZsdW9yZXNjZW50IHBhcmFtZXRlcnMKYGBgCgpTaW1wbGlmeSB0aGUgc2FtcGxlIG5hbWVzCgpgYGB7cn0Kb3JpTmFtZXMgPC0gc2FtcGxlTmFtZXMoZGF0MCkKdG1wIDwtIHN0cl9zcGxpdChvcmlOYW1lcywgcGF0dGVybiA9ICJbIF9dKyIsIHNpbXBsaWZ5ID0gVFJVRSlbLGMoMSwgNSldCmNvbG5hbWVzKHRtcCkgPC0gYygiRGF0ZSIsICJUcmVhdG1lbnQiKQojdHJlYXRtZW50LmxldmVscyA8LSBjKCJtb2NrIiwgIjVDIiwgIjEwIiwgIjEwMCIsICIxMDAwIikKc2FtcGxlIDwtIGRhdGEuZnJhbWUodG1wKSAlPiUgCiAgbXV0YXRlKAogICAgRGF0ZSA9IG1keShEYXRlKSwKICAgIFRyZWF0bWVudCA9IGdzdWIoIlxcLmZjcyIsICIiLCBUcmVhdG1lbnQpLCAjIHJlbW92ZSBzdWZmaXgKICAgIFRyZWF0bWVudCA9IGZjdF9pbnNlcShUcmVhdG1lbnQpLAogICAgbmFtZSA9IHBhc3RlKGZvcm1hdChEYXRlLCAiJVklbSVkIiksIHBhc3RlMChUcmVhdG1lbnQsICJtTSIpLCBzZXAgPSAiXyIpCiAgKQpyb3duYW1lcyhzYW1wbGUpIDwtIG9yaU5hbWVzCmRhdCA8LSBkYXQwICMgbWFrZSBhIGNvcHkKcERhdGEoZGF0KSA8LSBzYW1wbGUKd3JpdGVfdHN2KHBEYXRhKGRhdCksIGZpbGUgPSAiLi4vaW5wdXQvMjAyNDA0MDUtbGluZWFyLWgybzItY2ctc2FtcGxlLnRzdiIpCmBgYAoKCiMgR2F0dGluZyBzdHJhdGVnaWVzIHsudGFic2V0fQojIyBMb2FkIGFsbCBnYXRlcyBmcm9tIHNwZWNpZmljYXRpb24gZmlsZQpgYGB7cn0Kc291cmNlKCIuLi9zY3JpcHQvMjAyNTAyMDYtRkdMLWZsb3ctZ2F0ZS1zcGVjaWZpY2F0aW9uLlIiKQpgYGAKCiMjIEdhdGluZyBmb3Igc2luZ2xldHMKPlRoZSBmb2xsb3dpbmcgZ2FwaGluZyBzdGVwcyBhcmUgdXNlZCB0byBnYXRlIHNpbmdsZXRzIGJ5IEZTQyBhbmQgU1NDIHZhbHVlcy4gT25seSBzaW5nbGV0cyBhcmUgaW5jbHVkZWQgaW4gYW5hbHlzaXMuCj5HYXRlIGZvciBvdXRsaWVyIAoKYGBge3J9CiNvdXRsaWVyLmdhdGUgPC0gcmVjdGFuZ2xlR2F0ZShmaWx0ZXJJZCA9ICItb3V0bGllciIsICJGU0MuSCIgPSBjKDEuMmU1LCAxZTYpLCAiU1NDLkgiID0gYygxZTIsIDFlNikpCmdnY3l0byhkYXRbMV0sIGFlcyh4ID0gRlNDLkgsIHkgPSBTU0MuSCksIHN1YnNldCA9ICJyb290IikgKwogIGdlb21faGV4KGJpbnMgPSA2NCkgKyBnZW9tX2dhdGUob3V0bGllci5nYXRlKSArIGZhY2V0X3dyYXAofm5hbWUsIG5jb2wgPSAyKSArIGdnY3l0b19wYXJfc2V0KGxpbWl0cyA9ICJpbnN0cnVtZW50IikKYGBgCkFkZCBnYXRlIHRvIEdTCmBgYHtyfQpncyA8LSBHYXRpbmdTZXQoZGF0KSAjIGNyZWF0ZSBhIEdhdGluZ1NldAojIHJlbmFtZSB0aGUgc2FtcGxlcwpzYW1wbGVOYW1lcyhncykgPC0gcERhdGEoZ3MpJG5hbWUKIyBhZGQgdGhlIG91dGxpZXIgZ2F0ZQpnc19wb3BfYWRkKGdzLCBvdXRsaWVyLmdhdGUsIHBhcmVudCA9ICJyb290IikKcmVjb21wdXRlKGdzKQpgYGAKCj5HYXRlIGZvciBzaW5nbGV0cwoKYGBge3IgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NH0Kc2NQYXJzIDwtIGdnY3l0b19wYXJfc2V0KGxpbWl0cyA9IGxpc3QoeCA9IGMoMCwxZTYpLCB5ID0gYygzMCwzMDApKSkKZXggPC0gU3Vic2V0KGRhdFtbMV1dLCBvdXRsaWVyLmdhdGUpCiNwb2x5Z29uIDwtIG1hdHJpeChjKDFlNSwgMWU1LCAxZTYsIDFlNiwgCiMgICAgICAgICAgICAgICAgICAgIDYwLCAxMDUsIDEzNSw2MCksIG5jb2wgPSAyKQojY29sbmFtZXMocG9seWdvbikgPC0gYygiRlNDLkgiLCAiRlNDLlciKQojc2luZ2xldC5nYXRlIDwtIHBvbHlnb25HYXRlKGZpbHRlcklkID0gInNpbmdsZXQiLCBib3VuZGFyaWVzID0gcG9seWdvbikKZ2djeXRvKGV4LCBhZXMoeCA9IEZTQy5ILCB5ID0gRlNDLlcpKSArIGdlb21faGV4KGJpbnMgPSAxMjgpICsgZ2VvbV9nYXRlKHNpbmdsZXQuZ2F0ZSkgKyBnZW9tX3N0YXRzKCkgKyBzY1BhcnMKYGBgCgoKQWRkIHRoaXMgZ2F0ZSB0byB0aGUgZ2F0aW5nU2V0CmBgYHtyfQpnc19wb3BfYWRkKGdzLCBzaW5nbGV0LmdhdGUsIHBhcmVudCA9ICItb3V0bGllciIsIG5hbWUgPSAic2luZ2xldCIpCnJlY29tcHV0ZShncykKYGBgCgojIyBHYXRlIGZvciBsaXZlIGNlbGxzClRoaXMgaXMgdGhlIGxpdmUgcG9wdWxhdGlvbiB3aXRoIHJlZCBmbHVvcmVzY2VuY2UgYmVsb3cgMTBeMi4yCgo+ICoqTWFpbiB0YWtlYXdheSoqCj4KPiAxLiBEaWZmZXJlbnQgZnJvbSB0aGUgbGFzdCAobG9nLWRpbHV0aW9uIHNlcmllcykgZXhwZXJpbWVudCwgd2hlcmUgd2Ugb2JzZXJ2ZWQgYSBsYXJnZSBkaWZmZXJlbmNlIGluICVsaXZlIGJldHdlZW4gdGhlIG1vY2sgYW5kIDEwMCBtTSB0cmVhdGVkIGNlbGxzLCBpbiB0aGlzIGV4cGVyaW1lbnQgdGhlIGRpZmZlcmVuY2Ugd2FzIG5vdCBvbmx5IHZhcmlhYmxlIGFjcm9zcyByZXBsaWNhdGVzIGJ1dCBhbHNvIG11Y2ggbW9yZSBtb2Rlc3QsIHdpdGggdGhlIGJpZ2dlc3QgY2hhbmdlIGZyb20gOTIlIHRvIDU2JQo+Cj4gMi4gJWxpdmUgZHJvcHMgdG8gemVybyBwcmFjdGljYWxseSBhdCAwLjVNIG9yIGFib3ZlLgoKYGBge3J9CnNjUGFycyA8LSBnZ2N5dG9fcGFyX3NldChsaW1pdHMgPSBsaXN0KHggPSBjKDAsMTBeNS41KSwgeSA9IGMoMCwxMF41LjUpKSkKZGF0ZXMgPC0gdW5pcXVlKHBEYXRhKGdzKSREYXRlKQojcG9seWdvbiA8LSBtYXRyaXgoYygwLCA1KjEwXjMsIDUqMTBeMywgMCwgIyBCTDEuSCwgZ3JlZW4KIyAgICAgICAgICAgICAgICAgICAgMTBeMi4yLCAxMF4yLjIsIDAsIDApLCMgQkwzLkgsIHJlZAojICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpCiNjb2xuYW1lcyhwb2x5Z29uKSA8LSBjKCJCTDEuSCIsICJCTDMuSCIpCiNsaXZlLmdhdGUgPC0gcG9seWdvbkdhdGUoZmlsdGVySWQgPSAibGl2ZSIsIC5nYXRlID0gcG9seWdvbikKcC5heGlzIDwtIGxpc3QoCiAgc2NhbGVfeF9sb2dpY2xlKGJyZWFrcyA9IDEwXmMoMiwzLDQsNSkpLAogIHNjYWxlX3lfbG9naWNsZShicmVha3MgPSAxMF5jKDIsMyw0LDUpKSwKICB0aGVtZSgKICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjEpLCBmYWNlID0gMikKICApCikKCmZvcihkYXRlIGluIGRhdGVzKXsKICBwIDwtIGdnY3l0byhnc1twRGF0YShncykkRGF0ZSA9PSBkYXRlXSwgYWVzKHggPSBCTDEuSCwgeSA9IEJMMy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogICAgZ2VvbV9oZXgoYmlucyA9IDEyOCkgKyAKICAgIGdlb21fZ2F0ZShsaXZlLmdhdGUpICsKICAgIGdlb21fc3RhdHMobG9jYXRpb24gPSAiZGF0YSIsIGFkanVzdCA9IGMoMC4wMDUsIDUpLCBkaWdpdHMgPSAxKSArIAogICAgbGFicyh0aXRsZSA9IHBhc3RlMCgiRGF0ZTogIiwgZGF0ZSkpICsKICAgIGZhY2V0X3dyYXAofiBmY3RfaW5zZXEoVHJlYXRtZW50KSkgKwogICAgcC5heGlzICsgc2NQYXJzCiAgcHJpbnQocCkKfQpgYGAKCkFkZCB0aGlzIGdhdGUgdG8gdGhlIGdhdGluZ1NldAoKYGBge3J9CmdzX3BvcF9hZGQoZ3MsIGxpdmUuZ2F0ZSwgcGFyZW50ID0gInNpbmdsZXQiLCBuYW1lID0gImxpdmUiKQpyZWNvbXB1dGUoZ3MpCmBgYAojIyBHYXRlIGZvciB0aGUgaW50ZXJtZWRpYXRlIHBvcHVsYXRpb24gd2l0aCBoaWdoIFNZVE85ClRoaXMgaXMgdGhlIGludGVybWVkaWF0ZSBwb3B1bGF0aW9uIHdpdGggaGlnaCBSZWQgYW5kIEdyZWVuLiBXZSBoeXBvdGhlc2l6ZSB0aGF0IHRoZXkgcmVwcmVzZW50IG94aWRhdGl2ZWx5IGRhbWFnZWQgY2VsbHMgd2l0aCBwYXJ0aWFsbHkgY29tcHJvbWlzZWQgcGxhc21hIG1lbWJyYW5lcywgcmVzdWx0aW5nIGluIG1vcmUgU1lUTzkgYWNjdW11bGF0aW9uIGJ1dCBub3QgYSBzaWduaWZpY2FudCBpbmNyZWFzZSBpbiBQSS4KCj4gKipNYWluIHRha2Vhd2F5KioKPgo+IDEuIEZvciBzb21lIHJlYXNvbiwgdGhlIHBlcmNlbnRhZ2UgcmVwb3J0ZWQgYnkgZ2VvbV9zdGF0cygpIGlzIHdheSBvZmYgZm9yIDAuNSAtIDFNIHRyZWF0ZWQgc2FtcGxlcwo+Cj4gMi4gJSBpbnRlcm1lZGlhdGUgcG9wdWxhdGlvbiBwZWFrZWQgYXQgMjUwIG1NIGRvc2UuIEFnYWluLCBmcm9tIDAuNU0gYW5kIHVwLCB3ZSBkb24ndCBzZWUgbXVjaCBkaXN0aW5jdGlvbiBhbW9uZyB0aGUgc2FtcGxlcy4KCmBgYHtyfQojcG9seWdvbiA8LSBtYXRyaXgoYygxMF41LCAxKjEwXjMsIDEwXjUsCiMgICAgICAgICAgICAgICAgICAgIDEwXjIuMiwgMTBeMi4yLCAxMF40KSwgbmNvbCA9IDIpCiNwb2x5Z29uIDwtIG1hdHJpeChjKDEwXjMsIDEwXjUuNSwgMTBeNS41LCAgICMgQkwxLkgsIGdyZWVuCiMgICAgICAgICAgICAgICAgICAgIDEwXjIuMiwgMTBeMi4yLCAxMF40LjUpLCMgQkwzLkgsIHJlZAojICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpCiNjb2xuYW1lcyhwb2x5Z29uKSA8LSBjKCJCTDEuSCIsICJCTDMuSCIpCiNpbnRlci5nYXRlIDwtIHBvbHlnb25HYXRlKGZpbHRlcklkID0gImludGVyIiwgLmdhdGUgPSBwb2x5Z29uKQpmb3IoZGF0ZSBpbiBkYXRlcyl7CiAgcCA8LSBnZ2N5dG8oZ3NbcERhdGEoZ3MpJERhdGUgPT0gZGF0ZV0sIGFlcyh4ID0gQkwxLkgsIHkgPSBCTDMuSCksCiAgICAgICAgICAgICAgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogICAgZ2VvbV9oZXgoYmlucyA9IDEyOCkgKyAKICAgIGdlb21fZ2F0ZShpbnRlci5nYXRlKSArIAogICAgZ2VvbV9zdGF0cyhsb2NhdGlvbiA9ICJkYXRhIiwgYWRqdXN0ID0gYygwLjA1LCA1KSkgKyAKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoIkRhdGU6ICIsIGRhdGUpKSArCiAgICBmYWNldF93cmFwKH4gZmN0X2luc2VxKFRyZWF0bWVudCkpICsKICAgIHAuYXhpcyArIHNjUGFycwogIHByaW50KHApCn0KYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpnc19wb3BfYWRkKGdzLCBpbnRlci5nYXRlLCBwYXJlbnQgPSAic2luZ2xldCIsIG5hbWUgPSAiaW50ZXJtZWRpYXRlIikKcmVjb21wdXRlKGdzKQpgYGAKCiMjIFBsb3QgdG8gaWxsdXN0cmF0ZSBzdGFpbmluZyBwYXR0ZXJuClNob3cgYW4gZXhhbXBsZSBvZiB0aGUgc3RhaW5pbmcgcGF0dGVybiB3aXRoIG9uZSByZXBsaWNhdGUKYGBge3J9CnNjUGFycyA8LSBnZ2N5dG9fcGFyX3NldChsaW1pdHMgPSBsaXN0KHggPSBjKDAsMTBeNSksIHkgPSBjKDAsMTBeNCkpKQpwLmV4IDwtIGdnY3l0byhnc1twRGF0YShncykkRGF0ZSA9PSAiMjAyNC0wNC0xMCJdLCAKICAgICAgICAgICAgICAgYWVzKHggPSBCTDEuSCwgeSA9IEJMMy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogIGdlb21faGV4KGJpbnMgPSA2NCkgKyAKICBnZW9tX2dhdGUoImxpdmUiLCBjb2xvdXIgPSAiZ3JheTIwIikgKyAKICAjZ2VvbV9zdGF0cyhsb2NhdGlvbiA9ICJkYXRhIiwgYWRqdXN0ID0gYygwLjA1LCA1KSkgKyAKICBsYWJzKHRpdGxlID0gTlVMTCkgKwogIGZhY2V0X3dyYXAofiBmY3RfaW5zZXEoVHJlYXRtZW50KSkgKwogIHAuYXhpcyArIHNjUGFycwpwLmV4Cmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjUwMTIwLWxpbmVhci1oMm8yLWV4YW1wbGUtRkdMLXN0YWluaW5nLnBuZyIsIAogICAgICAgcGxvdCA9IHAuZXggKyBsYWJzKHRpdGxlID0gTlVMTCwgeCA9IE5VTEwsIHkgPSBOVUxMKSArCiAgICAgICAgIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjgpLCBmYWNlID0gMSksCiAgICAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuOCkpKSwKICAgICAgIHdpZHRoID0gMy42LCBoZWlnaHQgPSAzLjIpCmBgYAoKIyBFeHRyYWN0IGdhdGVkIHN0YXRzIGFuZCBNRkkKCiUgb2YgZXZlbnRzIGluIGVhY2ggb2YgdGhlIHRocmVlIGdhdGVzCmBgYHtyfQojIHdlIGFyZSBvbmx5IGludGVyZXN0ZWQgaW4gdGhlIHBvcHVsYXRpb25zIGFmdGVyIHNpbmdsZXQgZ2F0aW5nCm5vZGVzIDwtIGMoInNpbmdsZXQiLCAiaW50ZXJtZWRpYXRlIiwgImxpdmUiKQojIGdldCB0aGUgZXZlbnQgY291bnQKZ2F0ZWRfY250IDwtIGdzX3BvcF9nZXRfc3RhdHMoZ3MsIG5vZGVzLCB0eXBlID0gImNvdW50IikKIyBnZXQgdGhlIE1GSSBmb3IgZWFjaCBwYXJhbWV0ZXIgaW4gZWFjaCBwb3B1bGF0aW9uIG9mIGludGVyZXN0CmdhdGVkX21maSA8LSBnc19wb3BfZ2V0X3N0YXRzKGdzLCBub2RlcywgdHlwZSA9IHBvcC5NRkkpICU+JSAKICBzZWxlY3Qoc2FtcGxlLCBwb3AsIHN0YXJ0c193aXRoKCJGdW5nYUxpZ2h0IikpCmBgYAoKQ29tYmluZSB0aGUgZGF0YSBhbmQgbWV0YSBkYXRhCmBgYHtyfQpnYXRlZF9zdGF0cyA8LSBmdWxsX2pvaW4oZ2F0ZWRfY250LCBnYXRlZF9tZmksIGJ5ID0gYygic2FtcGxlIiwgInBvcCIpKSAlPiUgCiAgcmlnaHRfam9pbihwRGF0YShncyksIGJ5ID0gYygic2FtcGxlIiA9ICJuYW1lIikpICU+JSAKICByZWxvY2F0ZShEYXRlLCBUcmVhdG1lbnQsIC5hZnRlciA9IHNhbXBsZSkgJT4lIAogIHJlbG9jYXRlKHNhbXBsZSwgLmFmdGVyID0gbGFzdF9jb2woKSkgJT4lIAogIGFycmFuZ2UoRGF0ZSwgYXMubnVtZXJpYyhUcmVhdG1lbnQpKQp3cml0ZV90c3YoZ2F0ZWRfc3RhdHMsIGZpbGUgPSAiLi4vb3V0cHV0LzIwMjQwNDA1LWxpbmVhci1oMm8yLUNnLWdhdGVkLXN0YXRzLnRzdiIpCgojIHdlIGRvbid0IG5lZWQgdGhlIE1GSSBmb3IgdGhlIGxhdHRlciBhbmFseXNpcy4gYWRkIG1ldGEgZGF0YSB0byBnYXRlZF9jbnQKZ2F0ZWRfZnJlcSA8LSBsZWZ0X2pvaW4oc2FtcGxlLCBnYXRlZF9jbnQsIGJ5ID0gYygibmFtZSIgPSAic2FtcGxlIikpICU+JSAKICBzZWxlY3QoLW5hbWUpICU+JSAKICBncm91cF9ieShEYXRlLCBUcmVhdG1lbnQpICU+JSAKICBtdXRhdGUocGVyYyA9IGNvdW50IC8gY291bnRbcG9wID09ICJzaW5nbGV0Il0sIC5hZnRlciA9IGNvdW50LAogICAgICAgICBUcmVhdG1lbnQgPSBmY3RfaW5zZXEoVHJlYXRtZW50KSkgJT4lIAogIGFycmFuZ2UoRGF0ZSwgVHJlYXRtZW50KQpgYGAKCmBgYAojZ2F0ZWRfc3RhdHMgPC0gZ3NfcG9wX2dldF9zdGF0cyhncywgdHlwZSA9ICJjb3VudCIpICU+JSAKIyAgYXNfdGliYmxlKCkgJT4lIAojICBtdXRhdGUocG9wID0gZ3N1YigiLiovIiwgIiIsIHBvcCksIHBvcCA9IGdzdWIoIi1vdXRsaWVyIiwgImNlbGxzIiwgcG9wKSkgJT4lIAojICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcG9wLCBuYW1lc19wcmVmaXggPSAibl8iLCB2YWx1ZXNfZnJvbSA9IGNvdW50KSAlPiUgCiMgIG11dGF0ZSgKIyAgICAjcF9zaW5nbGV0ID0gbl9zaW5nbGV0IC8gbl9jZWxscywKIyAgICBwX2xpdmUgPSBuX2xpdmUgLyBuX3NpbmdsZXQsCiMgICAgcF9pbnRlcm1lZGlhdGUgPSBuX2ludGVybWVkaWF0ZSAvIG5fc2luZ2xldCwKIyAgICBwX2RlYWQgPSAxIC0gcF9saXZlIC0gcF9pbnRlcm1lZGlhdGUKIyAgKQojd3JpdGVfdHN2KGdhdGVkX2RhdGEsIGZpbGUgPSAiLi4vSW5wdXQvMjAyNDAxMjQtZmlnLTItRHllLU9yZGVyLWdhdGVkLWh0LnRzdiIpCiNwcmludChnYXRlZF9kYXRhKQpgYGAKCmBgYApmaW5hbCA8LSBzZWxlY3QocERhdGEoZGF0KSwgc2FtcGxlID0gbmFtZSwgZXZlcnl0aGluZygpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChnYXRlZF9zdGF0cywgLXN0YXJ0c193aXRoKCJuXyIpKSwgIGJ5ID0gInNhbXBsZSIpICU+JSAKICBsZWZ0X2pvaW4ocG9wTUZJLCBieSA9ICJzYW1wbGUiKQoKd3JpdGVfdHN2KGZpbmFsLCBmaWxlID0gIi4uL291dHB1dC8xMi4wMy1nYXRlZC1vdXRwdXQtMjAyNDAyMTQudHN2IikKcHJpbnQoZmluYWwgJT4lIHNlbGVjdCgtc2FtcGxlKSkKYGBgCgojIENvbXBhcmUgd2l0aCBDRlUKIyMgUmVhZCBDRlUgZGF0YSAKSGVyZSBhcmUgdGhlIHJhdyBjZnUgZGF0YQpgYGB7cn0KY2Z1X3JhdyA8LSByZWFkX3RzdigiLi4vaW5wdXQvMjAyNDAyMTQtMDQwNS1oMm8yLUNnLUNGVS1yYXcudHN2IiwKICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSAiY2NjY2NjaWlpaSIsIGNvbW1lbnQgPSAiIyIpCmNmdV9jYWxjIDwtIGNmdV9yYXcgJT4lIAogIHNlbGVjdChEYXRlLCBUcmVhdG1lbnQgPSBIMk8yX21NLCBHcm91cCwgRGlsdXRpb24sIFRvdGFsKSAlPiUgCiAgbXV0YXRlKERhdGUgPSB5bWQoRGF0ZSksCiAgICAgICAgIFRyZWF0bWVudCA9IGZjdF9pbnNlcShUcmVhdG1lbnQpLAogICAgICAgICBDRlUgPSBEaWx1dGlvbiAqIFRvdGFsKSAlPiUgCiAgIyB3ZSBvbmx5IG5lZWQgdGhlIGxpbmVhciByYW5nZSBleHBlcmltZW50CiAgZHBseXI6OmZpbHRlcihEYXRlID4geW1kKCIyMDI0MDQwMSIpKSAlPiUgCiAgIyBncm91cCBieSBEYXRlIHRvIGNhbGN1bGF0ZSB0aGUgcmF0aW8gb2YgTU8gdG8gTU0KICBncm91cF9ieShEYXRlKSAlPiUgCiAgbXV0YXRlKHBfbGl2ZSA9IENGVSAvIENGVVtHcm91cCA9PSAiTU0iXSkKYGBgCgojIyBDYWxjdWxhdGUgc3Vydml2YWwgZnJvbSBGdW5nYUxpZ2h0CgpXZSBjYWxjdWxhdGUgdGhlIHBlcmNlbnQgbGl2ZSBhcyB0aGUgRkdMIHN1cnZpdmFsLiBXZSBhbHNvIHJlY29yZCB0aGUgcGVyY2VudCBpbnRlcm1lZGlhdGUgZXZlbnRzIGFuZCB3aWxsIGludmVzdGlnYXRlIGl0cyB1dGlsaXR5IGZvciBkaXN0aW5ndWlzaGluZyBkb3NlcyBub3QgZGlzdGluZ3Vpc2hhYmxlIGJ5IENGVS4KYGBge3J9CmR5ZV9iYXNlZCA8LSBnYXRlZF9mcmVxICU+JSAKICAjIHJlY29yZCB0aGUgdG90YWwgbnVtYmVyIG9mIGV2ZW50cyBhcyB0aGUgY291bnQgb2Ygc2luZ2xldHMKICBncm91cF9ieShEYXRlLCBUcmVhdG1lbnQpICU+JSAKICBtdXRhdGUodG90YWwgPSBjb3VudFtwb3AgPT0gInNpbmdsZXQiXSkgJT4lIAogICMgbm93IHdlIGRvbid0IG5lZWQgdGhlIHNpbmdsZXQgcG9wdWxhdGlvbiBhbmQgdGhlIGNvdW50IHZhcmlhYmxlCiAgc2VsZWN0KC1jb3VudCkgJT4lIAogIGRwbHlyOjpmaWx0ZXIocG9wICE9ICJzaW5nbGV0IikgJT4lCiAgI3VuZ3JvdXAoKSAlPiUgCiAgIyB3ZSB3aWxsIHBpdm90IHRoaXMgZGF0YSBmcmFtZSB0byBhIHdpZGVyIGZvcm1hdCwgbWFraW5nIAogICMgdHdvIG5ldyB2YXJpYWJsZXMgb3V0IG9mIHRoZSBwZXJjZW50YWdlIHZhcmlhYmxlCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHBvcCwgdmFsdWVzX2Zyb20gPSBwZXJjLCBuYW1lc19wcmVmaXggPSAicF8iKSAlPiUgCiAgbXV0YXRlKHBfZGVhZCA9IDEgLSBwX2xpdmUgLSBwX2ludGVybWVkaWF0ZSkgJT4lIAogIHJlbG9jYXRlKHBfbGl2ZSwgLmFmdGVyID0gdG90YWwpCmBgYApgYGAKUEkgPC0gZmluYWwgJT4lIAogIGRwbHlyOjpmaWx0ZXIoRHllID09ICJQSSIpICU+JSAKICBzZWxlY3QoRGF0ZSwgVHJlYXRtZW50LCBNZXRob2QgPSBEeWUsIFNjb3JlID0gcF9saXZlKQoKRkdMIDwtIGZpbmFsICU+JSAKICBkcGx5cjo6ZmlsdGVyKER5ZSA9PSAiQm90aCIpICU+JSAKICBtdXRhdGUoCiAgICB3RkdMID0gcF9saXZlICogMi9sb2coQkwxX2xpdmUsIDEwKQogICkgJT4lIAogIHNlbGVjdChEYXRlLCBUcmVhdG1lbnQsIHdGR0wsIEZHTCA9IHBfbGl2ZSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYyh3RkdMLCBGR0wpLCBuYW1lc190byA9ICJNZXRob2QiLCB2YWx1ZXNfdG8gPSAiU2NvcmUiKQogIAoKYWxsIDwtIGJpbmRfcm93cygKICBQSSwgRkdMLAogIG11dGF0ZShjZnUsIE1ldGhvZCA9ICJDRlUiKSAlPiUgcmVuYW1lKFNjb3JlID0gQ0ZVKQopIApgYGAKCiMjIFBsb3R0aW5nIHRoZSByZXN1bHRzCkNGVSBzdXJ2aXZhbApgYGB7cn0KcC5jZnUgPC0gY2Z1X2NhbGMgJT4lIAogIGdncGxvdChhZXMoeCA9IFRyZWF0bWVudCwgeSA9IHBfbGl2ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGZpbGwgPSAiZ3JheTcwIiwgd2lkdGggPSAwLjgpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IGFzLmNoYXJhY3RlcihEYXRlKSksIAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoMC4xKSwKICAgICAgICAgICAgIHNpemUgPSAxLjUpICsgCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDQ6NiwgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhOQSwgMS4wNSksIGJyZWFrcyA9IHNlcSgwLDEsMC41KSkgKwogIGxhYnModGl0bGUgPSAiQ0ZVIiwgeCA9IGJxdW90ZShIWzJdKk9bMl1+KG1NKSksIHkgPSAiJSBMaXZlIikgKwogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpLCBmYWNlID0gMiksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCnAuY2Z1CmBgYAoKRnVuZ2FMaWdodCByZXN1bHRzCmBgYHtyfQpwLmR5ZSA8LSBkeWVfYmFzZWQgJT4lIAogIGdncGxvdChhZXMoeCA9IFRyZWF0bWVudCwgeSA9IHBfbGl2ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGZpbGwgPSAiZ3JheTcwIiwgd2lkdGggPSAwLjgpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IGFzLmNoYXJhY3RlcihEYXRlKSksIAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoMC4xKSwKICAgICAgICAgICAgIHNpemUgPSAxLjUpICsgCiAgIyBvdmVybGF5IHRoZSBwX2ludGVybWVkaWF0ZSBwb2ludHMKICBzdGF0X3N1bW1hcnkoYWVzKHkgPSBwX2ludGVybWVkaWF0ZSksIGdlb20gPSAicG9pbnQiLCBzaGFwZSA9IDk1LAogICAgICAgICAgICBmdW4gPSAibWVhbiIsIHNpemUgPSA1LCBjb2xvciA9ICJzdGVlbGJsdWUzIikgKwogIHN0YXRfc3VtbWFyeShhZXMoeSA9IHBfaW50ZXJtZWRpYXRlLCBncm91cCA9IE5BKSwgZ2VvbSA9ICJsaW5lIiwKICAgICAgICAgICAgZnVuID0gIm1lYW4iLCBjb2xvciA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IHBfaW50ZXJtZWRpYXRlLCBzaGFwZSA9IGFzLmNoYXJhY3RlcihEYXRlKSksCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjEpLAogICAgICAgICAgICAgY29sb3IgPSAic3RlZWxibHVlIiwgc2l6ZSA9IDEuNSwgc3Ryb2tlID0gMS41KSArIAogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSA0OjYsIGd1aWRlID0gIm5vbmUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCwgCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoTkEsIDEuMDUpLCBicmVha3MgPSBzZXEoMCwxLDAuNSkpICsKICBsYWJzKHRpdGxlID0gIkZ1bmdhTGlnaHQiLCB4ID0gYnF1b3RlKEhbMl0qT1syXX4obU0pKSwgeSA9ICIlIExpdmUiKSArCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMiksIGZhY2UgPSAyKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKcC5keWUKYGBgCgpBbHRlcm5hdGl2ZSBiYXIgcGxvdHMKYGBge3J9CnAuZHllLnNpZGVfYnlfc2lkZSA8LSBkeWVfYmFzZWQgJT4lIAogIHNlbGVjdChEYXRlLCBUcmVhdG1lbnQsIHBfbGl2ZSwgcF9pbnRlcm1lZGlhdGUpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMocF9saXZlLCBwX2ludGVybWVkaWF0ZSksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJwYXIiLCB2YWx1ZXNfdG8gPSAicGVyYyIpICU+JSAKICBtdXRhdGUocGFyID0gZmFjdG9yKHBhciwgbGV2ZWxzID0gYygicF9saXZlIiwgInBfaW50ZXJtZWRpYXRlIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIlIGxpdmUiLCAiJSBpbnRlcm1lZGlhdGUiKSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBwZXJjLCBncm91cCA9IHBhcikpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IHBhciksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwKICAgICAgICAgICBzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIHdpZHRoID0gMC44KSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBhcy5jaGFyYWN0ZXIoRGF0ZSksIGNvbG9yID0gcGFyKSwgCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9kZ2Uud2lkdGggPSAwLjkpLAogICAgICAgICAgICAgc2l6ZSA9IDEuMikgKyAKICBzY2FsZV9maWxsX21hbnVhbChOVUxMLCB2YWx1ZXMgPSBjKCJncmF5NzAiLCAibGlnaHRibHVlMiIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKE5VTEwsIHZhbHVlcyA9IGMoImJsYWNrIiwgInN0ZWVsYmx1ZSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDQ6NiwgZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhOQSwgMS4wNSksIGJyZWFrcyA9IHNlcSgwLDEsMC41KSkgKwogIGxhYnModGl0bGUgPSAiRnVuZ2FMaWdodCIsIHggPSBicXVvdGUoSFsyXSpPWzJdfihtTSkpLCB5ID0gTlVMTCkgKwogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpLCBmYWNlID0gMiksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiaW5zaWRlIiwKICAgICAgICBsZWdlbmQucG9zaXRpb24uaW5zaWRlID0gYygwLjgsIDAuOSkpCgpwLmR5ZS5zaWRlX2J5X3NpZGUKYGBgCkFzc2VtYmxlIHRoZSBwbG90CmBgYHtyfQpwbG90X2dyaWQoCiAgcC5jZnUgKyBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43KSkpLAogIHAuZHllLnNpZGVfYnlfc2lkZSArIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCiAgICB0aGVtZSh0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNykpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC43KSksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLAogIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMSwgMS4yKQopCmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjUwMTIwLWxpbmVhci1oMm8yLUNGVS1GR0wtY29tcGFyZS5wbmciLAogICAgICAgd2lkdGggPSAzLjEsIGhlaWdodCA9IDMuMSkKYGBgCiMjIFN0YXRpc3RpY2FsIHRlc3RzCldlIHVzZSBUdWtleSBIU0QgdGVzdCB0byBjb21wYXJlIGFsbCBwYWlycyBvZiBjb25kaXRpb25zbiBmb3IgQ0ZVCmBgYHtyfQp0bXAgPC0gYW92KHBfbGl2ZSB+IFRyZWF0bWVudCwgZGF0YSA9IGNmdV9jYWxjKQpUdWtleUhTRCh0bXApCmBgYAoKRm9yIHBfbGl2ZSB3aXRoIEZ1bmdhTGlnaHQKYGBge3J9CnRtcCA8LSBhb3YocF9saXZlIH4gVHJlYXRtZW50LCBkYXRhID0gZHllX2Jhc2VkKQpUdWtleUhTRCh0bXApCmBgYAoKRm9yIHBfaW50ZXJtZWRpYXRlIHdpdGggRnVuZ2FMaWdodApgYGB7cn0KdG1wIDwtIGFvdihwX2ludGVybWVkaWF0ZSB+IFRyZWF0bWVudCwgZGF0YSA9IGR5ZV9iYXNlZCkKVHVrZXlIU0QodG1wKQpgYGAKCgpgYGAKcGxvdF9ncmlkKAogIHAuY2Z1ICsgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsgY29vcmRfZmxpcCgpLAogIHAuZHllICsgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsgY29vcmRfZmxpcCgpICsgCiAgICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSwKICByZWwKKQpgYGAKCi0tLQoKYGBgCmFsbCAlPiUgCiAgZHBseXI6OmZpbHRlcighVHJlYXRtZW50ICVpbiUgYygibW9jayIsICI1QyIpLCBNZXRob2QgIT0gIndGR0wiKSAlPiUgCiAgbXV0YXRlKE1ldGhvZCA9IGZjdF9yZWxldmVsKE1ldGhvZCwgIkNGVSIsICJGR0wiLCAiUEkiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFRyZWF0bWVudCwgeSA9IFNjb3JlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgZmlsbCA9ICJncmF5IikgKwogICNnZW9tX3BvaW50KHNpemUgPSAyLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjA1KSkgKyAKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZGwiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEpLCAKICAgICAgICAgICAgICAgZ2VvbSA9ICJlcnJvcmJhciIsICB3aWR0aCA9IDAuMSkgKwogIGxhYnMoeCA9IGJxdW90ZShIWzJdKk9bMl1+KG1NKSksIHkgPSAiJSBMaXZlIikgKwogIGZhY2V0X3dyYXAofk1ldGhvZCwgbnJvdyA9IDEpICsKICB0aGVtZV9jb3dwbG90KCkgKwogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxLjIpLCBmYWNlID0gMiksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9vdXRwdXQvMjAyNDAzMjMtZm9yLVIzNS1DRlUtY29tcGFyZWQtd2l0aC1GR0wtYW5kLVBJLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMykKYGBgCgpFeGFtcGxlIG9mIHNhbXBsZS10by1zYW1wbGUgdmFyaWFiaWxpdHksIHVzaW5nIDEwMCBtTSB0cmVhdGVkIHNhbXBsZSBhcyBjYXNlCmBgYHtyfQpwIDwtIGdnY3l0byhnc1twRGF0YShncykkVHJlYXRtZW50ICVpbiUgYygiMTAwIiwgIjI1MCIpXSwKICAgICAgICAgICAgYWVzKHggPSBCTDEuSCwgeSA9IEJMMy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArCiAgZ2VvbV9oZXgoYmlucyA9IDY0KSArCiAgZ2VvbV9nYXRlKGxpdmUuZ2F0ZSkgKwogIGdlb21fc3RhdHMobG9jYXRpb24gPSAiZ2F0ZSIsIGFkanVzdCA9IGMoMiwgMC41KSwgZGlnaXRzID0gMSkgKwogIGZhY2V0X2dyaWQoVHJlYXRtZW50IH4gRGF0ZSkgKyAKICBsYWJzKHRpdGxlID0gTlVMTCkgKwogIHAuYXhpcyArIHNjUGFycwpwCmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjUwMjE0LWV4YW1wbGUtdmFyaWFiaWxpdHktYmV0d2Vlbi1yZXBsaWNhdGVzLnBuZyIsIAogICAgICAgd2lkdGggPSA1LCBoZWlnaHQgPSAzLjUpCmBgYAoKLS0tCgpCZWxvdyBhcmUgaGFueGkncyBwbG90dGluZyBjb2RlCjwhLS0tCmBgYHtyfQpjb21iaW5lZF9kYXRhIDwtIHJlYWRfdHN2KCIvc3BhY2UvaHRhbmc1L0RvY3VtZW50cy9GVU4xX2RhdGFfYW5hbHlzaXMvYmlvbC00Mzg2LWNvdXJzZS1wcm9qZWN0LWh0YW5nNS9NZXRob2RzIFBhcGVyIFdyaXRpbmcvMDItRnVuZ2FMaWdodC1EaXN0aW5ndWlzaGluZy1Qb3dlci9JbnB1dC8yMDI0MDIxOS1QSS1Cb3RoLURpc3Rpbmd1aXNoaW5nLVBvd2VyLWdhdGVkLUNGVS1odC50c3YiKQpwcmludChjb21iaW5lZF9kYXRhKQpjb21iaW5lZF9kYXRhICU+JSAKICBkcGx5cjo6ZmlsdGVyKER5ZSAlaW4lIGMoIkJvdGgiKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoVHJlYXRtZW50ICVpbiUgYygiMCIsICIxMCIsICIxMDAiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IEZHUywgeSA9IENGVV9TdXJ2aXZhbCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFRyZWF0bWVudCkpCgpjb21iaW5lZF9kYXRhICU+JSAKICBkcGx5cjo6ZmlsdGVyKER5ZSAlaW4lIGMoIkJvdGgiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFRyZWF0bWVudCwgeSA9IEZHUykpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IERhdGUpKQoKY29tYmluZWRfZGF0YSAlPiUgCiAgZHBseXI6OmZpbHRlcihEeWUgJWluJSBjKCJCb3RoIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBwZXJjZW50X2ludGVyKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gRGF0ZSkpCiNnZ3NhdmUoIi4uL291dHB1dC8yMDI0MDEwNC1QSS1EaWx1dGlvbnMtR2F0ZWRfUlAtUGxvdC5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDUpCmBgYAoKCmBgYHtyfQpjb21iaW5lZF9kYXRhJG5ld19GR1MgPC0gMSpjb21iaW5lZF9kYXRhJHBlcmNlbnRfTGl2ZSAtIDAuNipjb21iaW5lZF9kYXRhJHBlcmNlbnRfaW50ZXIgLSBjb21iaW5lZF9kYXRhJHBlcmNlbnRfRGVhZApwZjFnIDwtIGNvbWJpbmVkX2RhdGEgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKENGVV9TdXJ2aXZhbCwgbmV3X0ZHUyksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIkFzc2F5IiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIlN1cnZpdmFsIikgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIShEeWUgJWluJSBjKCJQSSIpKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIShUcmVhdG1lbnQgJWluJSBjKCI1QyIpKSkgICU+JQogICAgIG11dGF0ZShBc3NheSA9IGZhY3RvcihBc3NheSwgbGV2ZWxzID0gYygiQ0ZVX1N1cnZpdmFsIiwgIm5ld19GR1MiKSwgbGFiZWxzID0gYygiQ0ZVIiwgIkZHTCIpKSkgJT4lIAogICNtdXRhdGUoRGlsdXRpb24gPSBmYWN0b3IoRGlsdXRpb24sIGxldmVscyA9IGMoIjI1MCB4IiwgIjUwMCB4IiwgIjEwMDAgeCIsICIyMDAwIHgiKSkpICU+JQogIGdncGxvdChhZXMoeCA9IEFzc2F5LCB5ID0gU3Vydml2YWwpKSArCiAgZmFjZXRfd3JhcCh+IFRyZWF0bWVudCwgbnJvdyA9IDEsIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoYygiMCIgPSAiMCBtTSIsICIxMCIgPSAiMTAgbU0iLCAiMTAwIiA9ICIxMDAgbU0iLCAiMTAwMCIgPSAiMTAwMCBtTSIpKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX2NsX2Jvb3QiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQyIiwKICAgICAgICAgICAgICAgc2l6ZSA9IDAuOCwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4yKSkgKwogIGdlb21fcG9pbnQoc3Ryb2tlID0gMSwgc2l6ZSA9IDIsIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKDAuMDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCkgKwogIHRoZW1lX21pbmltYWwoKQoKcGYxZyArCiAgbGFicyh4ID0gIkFzc2F5IFR5cGUiLCB5ID0gIlN1cnZpdmFsIFF1YW50aWZpY2F0aW9uIikgKwogIHBhbmVsX2JvcmRlcihjb2xvciA9ICJibGFjayIsIHNpemUgPSAxLjUpICsKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gImJsYWNrIiksICAjIEFkanVzdCBzaXplIGFuZCBmYWNlIChib2xkKQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKQogICAgICAgICkrIAogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgCmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjQwMzAxLUNnLUxvZy1HYXRlZF8ucG5nIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA1KQpgYGAKCgoKCmBgYHtyfQpjb21iaW5lZF9kYXRhJHBlcmNlbnRfUElEZWFkIDwtIDEgLSAoY29tYmluZWRfZGF0YSRuX1BJRGVhZCAvIGNvbWJpbmVkX2RhdGEkbl9zaW5nbGV0KQpwIDwtIGNvbWJpbmVkX2RhdGEgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKENGVV9TdXJ2aXZhbCwgcGVyY2VudF9QSURlYWQpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJQSUFzc2F5IiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIlBJU3Vydml2YWwiKSAlPiUgCiAgZHBseXI6OmZpbHRlcighKER5ZSAlaW4lIGMoIkJvdGgiKSkpICU+JSAKICBkcGx5cjo6ZmlsdGVyKCEoVHJlYXRtZW50ICVpbiUgYygiNUMiKSkpICAlPiUKICAgICBtdXRhdGUoUElBc3NheSA9IGZhY3RvcihQSUFzc2F5LCBsZXZlbHMgPSBjKCJDRlVfU3Vydml2YWwiLCAicGVyY2VudF9QSURlYWQiKSwgbGFiZWxzID0gYygiQ0ZVIiwgIlBJIikpKSAlPiUgCiAgI211dGF0ZShEaWx1dGlvbiA9IGZhY3RvcihEaWx1dGlvbiwgbGV2ZWxzID0gYygiMjUwIHgiLCAiNTAwIHgiLCAiMTAwMCB4IiwgIjIwMDAgeCIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gUElBc3NheSwgeSA9IFBJU3Vydml2YWwpKSArCiAgZmFjZXRfd3JhcCh+IFRyZWF0bWVudCwgbnJvdyA9IDEsIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoYygiMCIgPSAiMCBtTSIsICIxMCIgPSAiMTAgbU0iLCAiMTAwIiA9ICIxMDAgbU0iLCAiMTAwMCIgPSAiMTAwMCBtTSIpKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX2NsX2Jvb3QiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQyIiwKICAgICAgICAgICAgICAgc2l6ZSA9IDAuOCwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4yKSkgKwogIGdlb21fcG9pbnQoc3Ryb2tlID0gMSwgc2l6ZSA9IDIsIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKDAuMDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCkgKwogIHRoZW1lX21pbmltYWwoKQoKcCArCiAgbGFicyh4ID0gIkFzc2F5IFR5cGUiLCB5ID0gIlN1cnZpdmFsIFF1YW50aWZpY2F0aW9uIikgKwogIHBhbmVsX2JvcmRlcihjb2xvciA9ICJibGFjayIsIHNpemUgPSAxLjUpICsKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gImJsYWNrIiksICAjIEFkanVzdCBzaXplIGFuZCBmYWNlIChib2xkKQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKQogICAgICAgICkrIAogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkgCmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjQwMzAxLUNnLUxvZy1HYXRlZC1QSS5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDUpCmBgYAoKYGBge3J9CnBmMWcgPC0gY29tYmluZWRfZGF0YSAlPiUKICBkcGx5cjo6ZmlsdGVyKCEoRHllICVpbiUgYygiQm90aCIpKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIShUcmVhdG1lbnQgJWluJSBjKCIxMDAwIiwgIjVDIikpKSAgJT4lCiAgI211dGF0ZShEaWx1dGlvbiA9IGZhY3RvcihEaWx1dGlvbiwgbGV2ZWxzID0gYygiMjUwIHgiLCAiNTAwIHgiLCAiMTAwMCB4IiwgIjIwMDAgeCIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVHJlYXRtZW50LCB5ID0gQ0ZVX1N1cnZpdmFsKSkgKwogIGZhY2V0X3dyYXAofiBEeWUsIHNjYWxlID0gImZyZWVfeSIpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChzdHJva2UgPSAxLCBzaXplID0gMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoMC4yKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICB0aGVtZV9taW5pbWFsKCkKcGYxZyArCiAgbGFicyh4ID0gIkh5ZHJvZ2VuIFBlcm94aWRlIFRyZWF0bWVudCBDb25jZW50cmF0aW9uIiwgeSA9ICJDRlUgU3Vydml2YWwiKSArCiAgcGFuZWxfYm9yZGVyKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEuNSkgKwogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siKSwgICMgQWRqdXN0IHNpemUgYW5kIGZhY2UgKGJvbGQpCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpCiAgICAgICAgKSsgCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpKSAKI2dnc2F2ZSgiLi4vb3V0cHV0LzIwMjQwMTA0LVBJLURpbHV0aW9ucy1HYXRlZF9SUC1QbG90LnBuZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNSkKYGBgCi0tLT4K